import { usePlugin, S3Handler } from "./plugin";

export function useS3<T>(handler: S3Handler<T>): Promise<T> {
    return usePlugin('@sker/s3', handler)
}

import { HeadObjectCommand, ListBucketsCommand, ListBucketsCommandInput, PutObjectCommand } from '@aws-sdk/client-s3'
export function useListBucketsCommand(cmd: ListBucketsCommandInput) {
    return useS3(async c => {
        return await c.send(new ListBucketsCommand(cmd))
    })
}

import { GetObjectCommand, GetObjectCommandInput, DeleteObjectCommand } from '@aws-sdk/client-s3'

export function useGetObjectCommand(cmd: GetObjectCommandInput) {
    return useS3(async c => {
        return await c.send(new GetObjectCommand(cmd))
    })
}
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { Request } from "express";
export interface SignedUrlOptions {
    expiresIn?: number;
    unhoistableHeaders?: Set<string>;
    signableHeaders?: Set<string>;
    unsignableHeaders?: Set<string>;
    signingDate?: number | string | Date;
    signingService?: string;
    signingRegion?: string;
}
export function useSignedUrl(cmd: GetObjectCommand, options?: SignedUrlOptions): Promise<string>;
export function useSignedUrl(cmd: DeleteObjectCommand, options?: SignedUrlOptions): Promise<string>;
export function useSignedUrl(cmd: any, options?: SignedUrlOptions) {
    return useS3(async (s3, config) => {
        const url = await getSignedUrl(s3, cmd, {
            signingDate: options?.signingDate,
            signingService: options?.signingService,
            signingRegion: options?.signingRegion,
            expiresIn: options?.expiresIn,
            unhoistableHeaders: options?.unhoistableHeaders,
            signableHeaders: options?.signableHeaders,
            unsignableHeaders: options?.unsignableHeaders
        });
        return url;
    })
}
export function useGetObjectCommandSignedUrl(cmd: GetObjectCommandInput, options?: SignedUrlOptions) {
    return useSignedUrl(new GetObjectCommand(cmd), options)
}

export function useS3Preview(key: string, options?: SignedUrlOptions) {
    return useS3(async (s3, config) => {
        const command = new GetObjectCommand({
            Bucket: config.privateBucket,
            Key: key,
        });
        const url = await getSignedUrl(s3, command, {
            signingDate: options?.signingDate,
            signingService: options?.signingService,
            signingRegion: options?.signingRegion,
            expiresIn: options?.expiresIn,
            unhoistableHeaders: options?.unhoistableHeaders,
            signableHeaders: options?.signableHeaders,
            unsignableHeaders: options?.unsignableHeaders
        });
        return url;
    })
}

export function useS3UploadUrl(key: string, length: number, type: string, options?: SignedUrlOptions) {
    return useS3(async (s3, config) => {
        const bucket = config.privateBucket;
        const s3Priview = async (key: string) => {
            const command = new GetObjectCommand({
                Bucket: config.privateBucket,
                Key: key,
            });
            const url = await getSignedUrl(s3, command, {
                signingDate: options?.signingDate,
                signingService: options?.signingService,
                signingRegion: options?.signingRegion,
                expiresIn: options?.expiresIn,
                unhoistableHeaders: options?.unhoistableHeaders,
                signableHeaders: options?.signableHeaders,
                unsignableHeaders: options?.unsignableHeaders
            });
            return url;
        }
        const headObject = async (key: string) => {
            const command = new HeadObjectCommand({
                Bucket: bucket,
                Key: key.trim(),
            });
            return s3.send(command).catch(() => null);
        }
        const isObjectExists = async (key: string) => {
            const result = await headObject(key);
            return result?.$metadata?.httpStatusCode === 200;
        }
        const isExists = await isObjectExists(key);
        if (isExists) {
            const url = await s3Priview(key);
            return { key, exists: true, url: url };
        }
        const command = new PutObjectCommand({
            Bucket: config.privateBucket,
            Key: key,
            ContentLength: length,
            ContentType: type,
        });
        const url = await getSignedUrl(s3, command, {
            signingDate: options?.signingDate,
            signingService: options?.signingService,
            signingRegion: options?.signingRegion,
            expiresIn: options?.expiresIn,
            unhoistableHeaders: options?.unhoistableHeaders,
            signableHeaders: options?.signableHeaders,
            unsignableHeaders: options?.unsignableHeaders
        });
        return {
            key: command.input.Key,
            url,
            exists: false,
        };
    })
}

export function useS3PrivateUpload(req: Request) {
    return useS3(async (s3, config) => {
        const bucket = config.privateBucket;
        const contentLength = req.headers["content-length"]
        
    })
}